import BaseXform from './base-xform';

class ListXform extends BaseXform {
    constructor(options) {
        super();

        this.tag = options.tag;
        this.always = !!options.always;
        this.count = options.count;
        this.empty = options.empty;
        this.$count = options.$count || 'count';
        this.$ = options.$;
        this.childXform = options.childXform;
        this.maxItems = options.maxItems;
    }

    prepare(model, options) {
        const { childXform } = this;
        if (model) {
            model.forEach((childModel, index) => {
                options.index = index;
                childXform.prepare(childModel, options);
            });
        }
    }

    render(xmlStream, model) {
        if (this.always || (model && model.length)) {
            xmlStream.openNode(this.tag, this.$);
            if (this.count) {
                xmlStream.addAttribute(this.$count, (model && model.length) || 0);
            }

            const { childXform } = this;
            (model || []).forEach((childModel, index) => {
                childXform.render(xmlStream, childModel, index);
            });

            xmlStream.closeNode();
        } else if (this.empty) {
            xmlStream.leafNode(this.tag);
        }
    }

    parseXmlObject(node) {
        let hasValue = false
        if (node._name === this.tag) {
            this.model = []
            node._elements?.forEach((item) => {
                if (this.childXform.parseXmlObject(item)) {
                    this.parser = this.childXform;
                    this.model.push(this.parser.model);
                    this.parser = undefined;
                    if (this.maxItems && this.model.length > this.maxItems) {
                        throw new Error(`Max ${this.childXform.tag} count (${this.maxItems}) exceeded`);
                    }
                }

            });
            hasValue = true;
        }
        return hasValue;
    }

    parseOpen(node) {
        if (this.parser) {
            this.parser.parseOpen(node);
            return true;
        }
        switch (node.name) {
            case this.tag:
                this.model = [];
                return true;
            default:
                if (this.childXform.parseOpen(node)) {
                    this.parser = this.childXform;
                    return true;
                }
                return false;
        }
    }

    parseText(text) {
        if (this.parser) {
            this.parser.parseText(text);
        }
    }

    parseClose(name) {
        if (this.parser) {
            if (!this.parser.parseClose(name)) {
                this.model.push(this.parser.model);
                this.parser = undefined;

                if (this.maxItems && this.model.length > this.maxItems) {
                    throw new Error(`Max ${this.childXform.tag} count (${this.maxItems}) exceeded`);
                }
            }
            return true;
        }

        return false;
    }

    reconcile(model, options) {
        if (model) {
            const { childXform } = this;
            model.forEach(childModel => {
                childXform.reconcile(childModel, options);
            });
        }
    }
}

export default ListXform;
